﻿#region Copyright
// Copyright (c) 2011-2012 RaisingForce Team (Alikin Sergey)
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion

using System;
using System.Configuration;
using System.Diagnostics.Contracts;
using System.Windows;

namespace RaisingForce.Raise.Presentation
{
    sealed public class WindowSupportProvider
    {
        #region Constructors

        public WindowSupportProvider(
            ApplicationSettingsBase usingSettings,
            string windowHeightDoubleSetting,
            string windowWidthDoubleSetting,
            string windowIsMaximizedBooleanSetting)
        {
            if (usingSettings == null)
            {
                throw new ArgumentNullException("usingSettings");
            }
            if (windowHeightDoubleSetting == null)
            {
                throw new ArgumentNullException("windowHeightDoubleSetting");
            }
            if (windowWidthDoubleSetting == null)
            {
                throw new ArgumentNullException("windowWidthDoubleSetting");
            }
            if (windowIsMaximizedBooleanSetting == null)
            {
                throw new ArgumentNullException("windowIsMaximizedBooleanSetting");
            }
            Contract.EndContractBlock();
            this.usingSettings = usingSettings;
            this.windowHeightSetting = windowHeightDoubleSetting;
            this.windowWidthSetting = windowWidthDoubleSetting;
            this.windowIsMaximizedSetting = windowIsMaximizedBooleanSetting;
        }

        #endregion

        #region Private Delegated Functions

        private readonly string windowHeightSetting;

        private double GetWindowHeightSetting()
        {
            return (double)this.usingSettings[this.windowHeightSetting];
        }

        private void SetWindowHeightSetting(double value)
        {
            this.usingSettings[this.windowHeightSetting] = value;
        }

        private readonly string windowWidthSetting;

        private double GetWindowWidthSetting()
        {
            return (double)this.usingSettings[this.windowWidthSetting];
        }

        private void SetWindowWidthSetting(double value)
        {
            this.usingSettings[this.windowWidthSetting] = value;
        }

        private readonly string windowIsMaximizedSetting;

        private bool GetWindowIsMaximizedSetting()
        {
            return (bool)this.usingSettings[this.windowIsMaximizedSetting];
        }

        private void SetWindowIsMaximizedSetting(bool value)
        {
            this.usingSettings[this.windowIsMaximizedSetting] = value;
        }

        #endregion

        #region Private Members And Routines

        private readonly ApplicationSettingsBase usingSettings;

        private Window window;

        private double windowHeight;

        private double windowWidth;

        private bool windowIsMaximized;

        private void checkSupportAdded()
        {
            if (this.window == null)
            {
                throw new InvalidOperationException(
                    "Window support was not added yet. Use AddSupportForWindow method first.");
            }
        }

        private static WindowState getWindowState(bool windowIsMaximized)
        {
            return windowIsMaximized ?
                WindowState.Maximized :
                WindowState.Normal;
        }

        private void window_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (this.window.WindowState == WindowState.Normal)
            {
                this.windowHeight = e.NewSize.Height;
                this.windowWidth = e.NewSize.Width;
            }
            this.windowIsMaximized =
                this.window.WindowState == WindowState.Maximized;
        }

        #endregion

        #region Public Methods

        public void AddSupportForWindow(Window window)
        {
            if (window == null)
            {
                throw new ArgumentNullException("window");
            }
            Contract.EndContractBlock();
            if (this.window != window)
            {
                if (this.window != null)
                {
                    throw new InvalidOperationException(
                        "Support for another window has already been added.");
                }
                // Set window field
                this.window = window;
                // Set and save window height
                double windowHeight = this.GetWindowHeightSetting();
                this.window.Height = windowHeight;
                this.windowHeight = windowHeight;
                // Set and save window width
                double windowWidth = this.GetWindowWidthSetting();
                this.window.Width = windowWidth;
                this.windowWidth = windowWidth;
                // Set and save window state (is it maximized?)
                bool windowIsMaximized = this.GetWindowIsMaximizedSetting();
                this.window.WindowState = getWindowState(windowIsMaximized);
                this.windowIsMaximized = windowIsMaximized;
                // Add SizeChanged handler
                this.window.SizeChanged += this.window_SizeChanged;
            }
        }

        public void RemoveSupportForWindow()
        {
            this.checkSupportAdded();
            this.window.SizeChanged -= this.window_SizeChanged;
#if DEBUG
            this.windowHeight = 0;
            this.windowWidth = 0;
            this.windowIsMaximized = false;
#endif
        }

        public void LoadWindowSize()
        {
            this.checkSupportAdded();
            this.window.Height = this.GetWindowHeightSetting();
            this.window.Width = this.GetWindowWidthSetting();
            this.window.WindowState = getWindowState(
                this.GetWindowIsMaximizedSetting());
        }

        public void SaveWindowSize()
        {
            this.checkSupportAdded();
            this.SetWindowHeightSetting(this.windowHeight);
            this.SetWindowWidthSetting(this.windowWidth);
            this.SetWindowIsMaximizedSetting(this.windowIsMaximized);
            this.usingSettings.Save();
        }

        #endregion
    }
}
